/// File:   main.c
/// Author: greg.sandstrom@gmail.com
///
/// Scan the keyboard matrix by driving one of 19 outputs (Ports BH&G) low, and watching for inputs to be driven low (Port B)


#ifndef __main_c__
#define __main_c__

#include <zneo.h>
#include <sio.h>
#include <stdio.h>

#include "led.h"
#include "scanmatrix.h"

// Bit match 
#define BITMATCH(a,b) ((a&b)==b)

// if bit is high on a and low on b
#define BITTRANS(a,b,c) (((a&c)==c)&&((b&c)!=c))


#define PDIN_MASK 0xFF // use PD[0..7] as detector

#define PBOUT_MASK 0x00 // use PB[0..7] to scan
#define PHOUT_MASK 0xF0 // use PH[0..3] to scan
#define PGOUT_MASK 0x00 // use PF[0..7] to scan

unsigned int up(unsigned int scanc) {
	if (scanc == 0 || IS_MACRO(scanc)) {
		return 0;
	}

	if (scanc < 0xFF) {
		return 0xF000+scanc;
	}
	if ((scanc & 0xFF00)==0xE000) {
		return 0xE01000 + scanc;
	}
	return scanc;
}


//unsigned char volatile PxOUT;
#define PxOUT PEOUT

#define PULSE_CLOCK  PxOUT|=0x02;PxOUT&=~0x02;

int volatile pause_temp;
void pause (void) {
	unsigned char i;
	for (i=0;i<0xFF;++i) ++pause_temp;
}


/// Take in a byte and send out an 11 bit PS/2 frame.
void frame (unsigned char s) {
	char i = 0;
	unsigned char x, c=1;

	PxOUT = 0x00;
	PULSE_CLOCK 
	printf("0 ");
	pause();

	for (i=0;i<8;++i) {
		x=(s>>i)&0x01;
		c+=x;

		PxOUT = x;
		PULSE_CLOCK
		printf("%d", x);
		pause(); 
	}

	PxOUT = c&0x01;
	PULSE_CLOCK 
	printf(" %d", c&0x01);
	pause();

	PxOUT = 0x01;
	PULSE_CLOCK 
	printf(" 1\n");
}

void send_macro(unsigned int scanc);

/// Send the scancode.
///  Each scancode could contain multiple frames
///  (If key-up or extended key or macro)
void send (unsigned int scanc) {
	printf(">> %x\n", scanc&0xFFFF);
	if (scanc == 0x00) { return; }

	if (IS_MACRO(scanc)) {
		send_macro(scanc);
		return;
	}

	if (scanc>0x010000) {
		frame((scanc>>16)&0xFF);
	}
	if (scanc>0x0100) {
		frame((scanc>>8)&0xFF);
	}
	frame(scanc&0xFF);
}


void main (void) {

	unsigned short i;
	unsigned char d, d_;

	unsigned char ds [19]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
	
	// set output pins.
	PBDD &= PBOUT_MASK;
	PHDD &= PHOUT_MASK;
	PGDD &= PGOUT_MASK;

	PBPUE |= ~PBOUT_MASK;
	PHPUE |= ~PHOUT_MASK;
	PGPUE |= ~PGOUT_MASK;

	// set input pins
	PCDD |= PDIN_MASK;
	// enable pullup on input pins
	PCPUE |= PDIN_MASK;

	PEDD &= ~0x03;


    init_uart(_UART0, _DEFFREQ, 9600); 
	printf("Key Detect\n");

	for(i=0;i<19;++i) {
		printf("[%d]=", i);
		for(d=0;d<8;++d) {
			printf("%x,", scanmatrix[i][d]);
		}
		printf("\n");
	}

	i=0;

	while (1) {
		// By setting the non-scanning lines to input we can use tri-state to let them not pull our scan line high.
		if (i<8) {
			d=~(0x01<<i);
			PBDD  = d;
			PBOUT = d;
			PHDD  = 0xFF;
			PGDD  = 0xFF;
		} else if (i<12) {
			d=~(0x01<<(i-8));
			PBDD  = 0xFF;
			PHDD  = d;
			PHOUT = d;
			PGDD  = 0xFF;
		} else if (i<19) {
			d=~(0x01<<(i-12));
			PBDD  = 0xFF;
			PHDD  = 0xFF;
			PGDD  = d;
			PGOUT = d;
		}

		// read input
		d_ = ds[i];
		d = ((~PCIN) & PDIN_MASK);
		ds[i]=d;

		if (d_!=d) {
			printf("-----\n");
			printf("i: %d\n", i);

			//there's gotta be an "easier" way....

			// newly pressed keys....
			if (BITTRANS(d, d_, 0x01)) {
				printf("d: 0\n");
				send(scanmatrix[i][0]);
			}
			if (BITTRANS(d, d_, 0x02)) {
				printf("d: 1\n");
				send(scanmatrix[i][1]);
			}
			if (BITTRANS(d, d_, 0x04)) {
				printf("d: 2\n");
				send(scanmatrix[i][2]);
			}
			if (BITTRANS(d, d_, 0x08)) {
				printf("d: 3\n");
				send(scanmatrix[i][3]);
			}
			if (BITTRANS(d, d_, 0x10)) {
				printf("d: 4\n");
				send(scanmatrix[i][4]);
			}
			if (BITTRANS(d, d_, 0x20)) {
				printf("d: 5\n");
				send(scanmatrix[i][5]);
			}
			if (BITTRANS(d, d_, 0x40)) {
				printf("d: 6\n");
				send(scanmatrix[i][6]);
			}
			if (BITTRANS(d, d_, 0x80)) {
				printf("d: 7\n");
				send(scanmatrix[i][7]);
			}


			// newly released keys
			if (BITTRANS(d_, d, 0x01)) {
				printf("d: -0\n");
				send(up(scanmatrix[i][0]));
			}
			if (BITTRANS(d_, d, 0x02)) {
				printf("d: -1\n");
				send(up(scanmatrix[i][1]));
			}
			if (BITTRANS(d_, d, 0x04)) {
				printf("d: -2\n");
				send(up(scanmatrix[i][2]));
			}
			if (BITTRANS(d_, d, 0x08)) {
				printf("d: -3\n");
				send(up(scanmatrix[i][3]));
			}
			if (BITTRANS(d_, d, 0x10)) {
				printf("d: -4\n");
				send(up(scanmatrix[i][4]));
			}
			if (BITTRANS(d_, d, 0x20)) {
				printf("d: -5\n");
				send(up(scanmatrix[i][5]));
			}
			if (BITTRANS(d_, d, 0x40)) {
				printf("d: -6\n");
				send(up(scanmatrix[i][6]));
			}
			if (BITTRANS(d_, d, 0x80)) {
				printf("d: -7\n");
				send(up(scanmatrix[i][7]));
			}
		}

		// It seemed that the input was getting "confused"
		// so set no lines to scan, and read to "clear"
		PBOUT |= ~PBOUT_MASK;
		PHOUT |= ~PHOUT_MASK;
		PGOUT |= ~PGOUT_MASK;
		d = ((~PCIN) & PDIN_MASK);

		i = ((i+2)%19);
	}
}


/// Oh so ugly....
void pause_keydown() {
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
	pause();
}

void pause_betweenkeys() {
	pause();
	pause();
	pause();
	pause();
}

void send_whole(unsigned int scanc, unsigned char shifted) {
	if (shifted)
		send(SHFT);

	send(scanc);
	pause_keydown();
	send(up(scanc));

	if (shifted)
		send(up(SHFT));

	pause_betweenkeys();
}

void send_macro(unsigned int scanc) {
	if (scanc == HELP) {
		send_whole(__h_, 1);
		send_whole(__e_, 1);
		send_whole(__l_, 1);
		send_whole(__p_, 1);
	} else if (scanc == EJCT) {
		send_whole(__g_, 1);
		send_whole(__r_, 0);
		send_whole(__e_, 0);
		send_whole(__g_, 0);
		pause_betweenkeys();
		pause_betweenkeys();
		pause_betweenkeys();
		send_whole(__s_, 1);
		send_whole(__a_, 0);
		send_whole(__n_, 0);
		send_whole(__d_, 0);
		send_whole(__s_, 0);
		send_whole(__t_, 0);
		send_whole(__r_, 0);
		send_whole(__o_, 0);
		send_whole(__m_, 0);
	} else {
	}
}

#endif